﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;

namespace TaskFramework.Tests
{
    [TestFixture]
    public class TaskQueueFixture
    {
        [Test]
        public void should_queue_unique_root_tasks_and_ensure_simple_queue_behavior()
        {
            const int numberOfTasks = 20;
            ITaskTracker tracker = new TaskTracker();
            ITaskQueue queue = new TaskQueue(tracker);

            for (int i = 0; i < numberOfTasks; i++)
            {
                Task task = new QuickTask(new QuickTaskRequest());
                tracker.AddTask(task.TaskId);
                queue.Enqueue(new TaskInfo(task, null));
            }

            Assert.AreEqual(numberOfTasks, queue.Count);

            int firstTaskId = queue.Peek().Task.TaskId;
            int taskCount = queue.Count;

            for (int taskId = firstTaskId; taskId < firstTaskId + taskCount; taskId++)
            {
                Assert.AreEqual(taskId, queue.Dequeue().Task.TaskId);
            }
        }

        [Test]
        public void a_routed_task_should_jump_the_queue()
        {
            const int numberOfInitialTasks = 3;
            ITaskTracker tracker = new TaskTracker();
            ITaskQueue queue = new TaskQueue(tracker);

            for (int i = 0; i < numberOfInitialTasks; i++)
            {
                Task task = new QuickTask(new QuickTaskRequest());
                tracker.AddTask(task.TaskId);
                queue.Enqueue(new TaskInfo(task, null));
            }

            Assert.AreEqual(numberOfInitialTasks, queue.Count);

            int firstTaskId = queue.Peek().Task.TaskId;

            Task inserted = new QuickTask(new QuickTaskRequest());
            tracker.AddTask(inserted.TaskId, firstTaskId);
            queue.Enqueue(new TaskInfo(inserted, null, firstTaskId));

            int[] expectedTaskIds = new int[numberOfInitialTasks + 1];
            expectedTaskIds[0] = firstTaskId;
            expectedTaskIds[1] = firstTaskId + 3;
            expectedTaskIds[2] = firstTaskId + 1;
            expectedTaskIds[3] = firstTaskId + 2;

            Assert.AreEqual(expectedTaskIds.Length, queue.Count);

            for (int i = 0; i < expectedTaskIds.Length; i++)
            {
                TaskInfo dequeued = queue.Dequeue();
                Assert.AreEqual(expectedTaskIds[i], dequeued.Task.TaskId);
            }
        }

        [Test]
        public void a_routed_task_should_jump_the_queue_even_after_the_root_task_is_dequeued()
        {
            const int numberOfInitialTasks = 3;
            ITaskTracker tracker = new TaskTracker();
            ITaskQueue queue = new TaskQueue(tracker);

            for (int i = 0; i < numberOfInitialTasks; i++)
            {
                Task task = new QuickTask(new QuickTaskRequest());
                tracker.AddTask(task.TaskId);
                queue.Enqueue(new TaskInfo(task, null));
            }

            Assert.AreEqual(numberOfInitialTasks, queue.Count);

            int firstTaskId = queue.Peek().Task.TaskId;

            // dequeue only the first task
            queue.Dequeue();

            Task inserted = new QuickTask(new QuickTaskRequest());
            tracker.AddTask(inserted.TaskId, firstTaskId); // add the routed task to the tracker
            tracker.RemoveTask(firstTaskId);               // remove the root task from the tracker

            queue.Enqueue(new TaskInfo(inserted, null, firstTaskId));

            int[] expectedTaskIds = new int[numberOfInitialTasks];
            expectedTaskIds[0] = firstTaskId + 3;
            expectedTaskIds[1] = firstTaskId + 1;
            expectedTaskIds[2] = firstTaskId + 2;

            Assert.AreEqual(expectedTaskIds.Length, queue.Count);

            for (int i = 0; i < expectedTaskIds.Length; i++)
            {
                TaskInfo dequeued = queue.Dequeue();
                Assert.AreEqual(expectedTaskIds[i], dequeued.Task.TaskId);
            }
        }
    }
}
